﻿/**************************************************************
* Copyright (C) 2018 www.sf-info.cn 盛峰版权所有(盗版必究)
*
* 作者: 孙泽伟(QQ 1039318332)
* 创建时间: 2018/10/30 22:40:15
* 文件名: 
* 描述: 
* 
* 修改历史
* 修改人：
* 时间：
* 修改说明：
*
**************************************************************/
using Dapper;
using EIP.Agile.Models.Dtos.DataBase;
using EIP.Agile.Repository;
using EIP.Base.Models.Entities.Workflow;
using EIP.Base.Repository.Fixture;
using EIP.Common.Extension;
using EIP.Common.Models;
using EIP.Common.Models.Dtos;
using EIP.Common.Models.Resx;
using EIP.Common.Repository;
using EIP.Common.Util;
using EIP.Workflow.Engine.Models.Dtos;
using EIP.Workflow.Engine.Models.Dtos.Form;
using EIP.Workflow.Engine.Models.Dtos.ProcessInstance;
using EIP.Workflow.Models.Enums;
using MySql.Data.MySqlClient;
using Npgsql;
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.Data.SqlClient;
using System.IO;
using System.Linq;
using System.Threading.Tasks;

namespace EIP.Workflow.Engine.Logic
{
    /// <summary>
    /// 流程引擎表单
    /// </summary>
    public class WorkflowEngineFormLogic : IWorkflowEngineFormLogic
    {
        private readonly IAgileDataBaseRepository _systemDataBaseRepository;
        /// <summary>
        /// 
        /// </summary>
        /// <param name="systemDataBaseRepository"></param>
        public WorkflowEngineFormLogic(IAgileDataBaseRepository systemDataBaseRepository)
        {
            _systemDataBaseRepository = systemDataBaseRepository;
        }

        /// <summary>
        /// 初始化表单数据
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<IList<WorkflowEngineFormControlsOutput>> InitFormData(WorkflowEngineFormInitDataInput input)
        {
            IList<WorkflowEngineFormControlsOutput> outputs = new List<WorkflowEngineFormControlsOutput>();
            using (var fixture = new SqlDatabaseFixture())
            {
                var form = await fixture.Db.AgileConfig.FindAsync(f=>f.ConfigId==input.FormId);

                //拼接sql
                string sql = $"SELECT * FROM {form.DataFromName} WHERE RelationId='{ input.ProcessInstanceId}'";
                DataTable table = new DbHelper(( GetConnection()).Connection).CreateSqlDataTable(sql);
                //判断当前节点是否为开始节点
                WorkflowProcessInstance instance = new WorkflowProcessInstance();
                bool isStart = input.ActivityType == EnumAcitvityType.开始.FindDescription();
                if (!isStart)
                {
                    //获取流程实例发起人
                    instance = await fixture.Db.WorkflowProcessInstance.FindByIdAsync(input.ProcessInstanceId);
                }
                DataRow dr = null;
                IList<string> fields = new List<string>();
                if (table.Rows.Count > 0)
                {
                    dr = table.Rows[0];
                    foreach (DataColumn dc in table.Columns)
                    {
                        fields.Add(dc.ColumnName);
                    }
                }
                foreach (var control in input.Controls)
                {
                    //判断类型是否为附件
                    if (control.Type == "files")
                    {
                        //查找附件并拷贝附件插入
                        var files = await fixture.Db.SystemFile.FindAllAsync(f =>
                            f.CorrelationId == input.ProcessInstanceId + "|" + control.ColumnName);
                        foreach (var file in files)
                        {
                            file.FileId = CombUtil.NewComb();
                            file.CorrelationId = input.StartProcessInstanceId + "|" + control.ColumnName;
                            //拷贝文件
                            var uploadPath = ConfigurationUtil.GetUploadPath();
                            var path = file.Path.Split('/');
                            var fileName = path[path.Length - 1].Replace(file.Extension, "");
                            var orignFile = uploadPath + file.Path;
                            var newFilePath = file.Path.Replace(fileName, file.FileId.ToString());
                            var newFile = uploadPath + newFilePath;
                            File.Copy(orignFile, newFile, true);
                            file.Path = newFilePath;
                            await fixture.Db.SystemFile.InsertAsync(file);
                        }
                    }
                    else
                    {
                        //判断是否具有默认值
                        var output = new WorkflowEngineFormControlsOutput
                        {
                            Name = control.ColumnName,
                            Type = control.Type,
                            Value = control.Default.IsNotNullOrEmpty() ? SetDefaultValue(control.Default, input, isStart, instance) : null
                        };

                        //数据库读取数据
                        if (table.Rows.Count > 0)
                        {
                            if (fields.Any(a => a == control.ColumnName))
                                if (dr != null)
                                    output.Value = dr[control.ColumnName].ToString();
                        }
                        outputs.Add(output);
                        if (control.IsSingle == "false" || control.ColumnName.ToLower() == "radio" || control.ColumnName.ToLower() == "checkbox")
                        {
                            //判断是否具有默认值
                            var outputSingle = new WorkflowEngineFormControlsOutput
                            {
                                Name = control.ColumnName,
                                Type = control.Type,
                                Value = control.Default.IsNotNullOrEmpty() ? SetDefaultValue(control.Default, input, isStart, instance) : null
                            };

                            //数据库读取数据
                            if (table.Rows.Count > 0)
                            {
                                if (fields.Any(a => a == control.ColumnName))
                                    if (dr != null)
                                        outputSingle.Value = dr[control.ColumnName].ToString();
                            }
                            outputs.Add(outputSingle);
                        }
                    }
                }
            }
            return outputs;
        }

        /// <summary>
        /// 获取审批人员
        /// </summary>
        /// <param name="dataBaseId"></param>
        /// <param name="sql"></param>
        /// <returns></returns>
        public async Task<IEnumerable<WorkflowEngineProcessingPersonDetailOutput>> GetApproveUserBySql(Guid? dataBaseId, string sql)
        {
            var connection = dataBaseId.HasValue ? ( GetConnection()).Connection : ConfigurationUtil.GetSection("EIP:ConnectionString");
            using (var db = GetDbConnection(connection))
            {
                return await db.QueryAsync<WorkflowEngineProcessingPersonDetailOutput>(sql);
            }
        }

        /// <summary>
        /// 获取数据库连接
        /// </summary>
        /// <param name="connstring"></param>
        private DbConnection GetDbConnection(string connstring)
        {
            DbConnection conn;
            //判断执行类型
            var connectionType = ConfigurationUtil.GetSection("EIP:ConnectionType").ToLower();
            switch (connectionType)
            {
                case ResourceDataBaseType.Mysql:
                    conn = new MySqlConnection(connstring);
                    break;
                case ResourceDataBaseType.Postgresql:
                    conn = new NpgsqlConnection(connstring);
                    break;
                default:
                    conn = new SqlConnection(connstring);
                    break;
            }
            return conn;
        }
        /// <summary>
        /// 赋予默认值
        /// </summary>
        /// <param name="default"></param>
        /// <param name="input"></param>
        /// <param name="isStart"></param>
        /// <param name="instance"></param>
        /// <returns></returns>
        private string SetDefaultValue(string @default, WorkflowEngineFormInitDataInput input, bool isStart, WorkflowProcessInstance instance)
        {
            object value = string.Empty;
            switch (@default)
            {
                //当前处理人
                case "userid":
                    value = input.UserId;
                    break;
                case "usercode":
                    value = input.UserCode;
                    break;
                case "username":
                    value = input.UserName;
                    break;
                case "orgid":
                    value = input.OrganizationId;
                    break;
                case "orgname":
                    value = input.OrganizationName;
                    break;
                //流程发起人
                case "senduserid":
                    value = isStart ? input.UserId : instance.CreateUserId;
                    break;
                case "sendusername":
                    value = isStart ? input.UserName : instance.CreateUserName;
                    break;
                case "sendorgid":
                    value = isStart ? input.OrganizationId : instance.CreateUserOrganizationId;
                    break;
                case "sendorgname":
                    value = isStart ? input.OrganizationName : instance.CreateUserOrganizationName;
                    break;
                //发起时间
                case "sendshorttime":
                    value = isStart ? DateTime.Now.ToString("yyyy-MM-dd") : instance.CreateTime.ToString("yyyy-MM-dd");
                    break;
                case "sendlongtime":
                    value = isStart ? DateTime.Now.ToString("yyyy年MM月dd日") : instance.CreateTime.ToString("yyyy年MM月dd日");
                    break;
                case "sendshorttimemmhh":
                    value = isStart ? DateTime.Now.ToString("HH:mm") : instance.CreateTime.ToString("HH:mm");
                    break;
                case "sendlongtimemmhh":
                    value = isStart ? DateTime.Now.ToString("HH时mm分") : instance.CreateTime.ToString("HH时mm分");
                    break;
                case "sendshortdatetime":
                    value = isStart ? DateTime.Now.ToString("yyyy-MM-dd HH:mm") : instance.CreateTime.ToString("yyyy-MM-dd HH:mm");
                    break;
                case "sendlongdatetime":
                    value = isStart ? DateTime.Now.ToString("yyyy年MM月dd日 HH时mm分") : instance.CreateTime.ToString("yyyy年MM月dd日 HH时mm分");
                    break;

                //发起时间
                case "shorttime":
                    value = DateTime.Now.ToString("yyyy-MM-dd");
                    break;
                case "longtime":
                    value = DateTime.Now.ToString("yyyy年MM月dd日");
                    break;
                case "shorttimemmhh":
                    value = DateTime.Now.ToString("HH:mm");
                    break;
                case "longtimemmhh":
                    value = DateTime.Now.ToString("HH时mm分");
                    break;
                case "shortdatetime":
                    value = DateTime.Now.ToString("yyyy-MM-dd HH:mm");
                    break;
                case "longdatetime":
                    value = DateTime.Now.ToString("yyyy年MM月dd日 HH时mm分");
                    break;
            }

            return value.ToString();
        }
        /// <summary>
        /// 获取对应表列信息
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<OperateStatus<IEnumerable<AgileDataBaseColumnDto>>> FindDataBaseColumnsByProcessId(IdInput input)
        {
            var output = new List<AgileDataBaseColumnDto>();
            using (var fixture = new SqlDatabaseFixture())
            {
                var process = await fixture.Db.WorkflowProcess.FindAsync(f => f.ProcessId == input.Id);
                if (process.FormId != null)
                {
                    var form = await fixture.Db.AgileConfig.FindAsync(f => f.ConfigId == process.FormId);
                     output = (await _systemDataBaseRepository.FindDataBaseColumns(new AgileDataBaseTableDto
                    {
                        Name = form.DataFromName
                    })).ToList();
                }
                return OperateStatus<IEnumerable<AgileDataBaseColumnDto>>.Success(output);
            }
        }

        /// <summary>
        /// 保存表单数据
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<OperateStatus> SaveFormData(WorkflowEngineFormSaveDataInput input)
        {
            OperateStatus<Guid> operateStatus = new OperateStatus<Guid>();
            //主键Id
            Guid id = CombUtil.NewComb();

            try
            {

            }
            catch (Exception e)
            {
                operateStatus.Msg = "操作失败";
                operateStatus.Code = ResultCode.Error;
                throw e;
            }
            return operateStatus;
        }

        /// <summary>
        /// 删除表单数据
        /// </summary>
        /// <param name="inputs"></param>
        /// <returns></returns>
        public async Task<OperateStatus> DeleteFormData(IList<WorkflowEngineFormDeleteDataInput> inputs)
        {
            OperateStatus<Guid> operateStatus = new OperateStatus<Guid>();
            try
            {

            }
            catch (Exception e)
            {
                operateStatus.Msg = e.Message;
                operateStatus.Code = ResultCode.Error;
            }
            return operateStatus;
        }

        /// <summary>
        /// 获取连接字符串
        /// </summary>
        /// <param name="id"></param>
        private WorkflowEngineGetConnectionOutput GetConnection()
        {
            return new WorkflowEngineGetConnectionOutput
            {
                Connection = ConfigurationUtil.GetSection("EIP:ConnectionString")
            };
        }
      
        #region 事件

        /// <summary>
        /// 根据Api获取数据
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<object> EventDoByApi(WorkflowEngineEventDoByApiInput input)
        {
            if (input.DataString.IsNotNullOrEmpty())
            {
                input.Data = input.DataString.JsonStringToObject<WorkflowEngineEventDoByApiDataOutput>();
            }
            switch (input.Type.ToLower())
            {
                case "post":
                    return await RequestUtil.Post(input.Url, new
                    {
                        Controls = input.Data.Controls,
                        Task = input.Data.Task
                    }, input.Header);
                default:
                    return await RequestUtil.Get(input.Url, null, input.Header);
            }
        }
        #endregion
    }
}